---@class RedRob.PlayerAi : RedRob.AiBase
---@field actor RedRob.Player
local PlayerAi = RedRob.CreateClass("PlayerAi","AiBase")
function PlayerAi:OnCreate()
    self.destinationData = {isStart = false,isFinished = false,time = 0,maxTime = 0,
                            startPos = Vector3.New(),targetPos = Vector3.New(),
                            callback = nil,endDirection = -1,
                            sendMsgInterval = 1,sendMsgTime = 0} --目的地数据
    self.PursuitData = {isStart = false,inRangeRadius = 1,callback = nil,target = nil,isWait = false,useCenter = false}   --追击目标进入范围内回调
    self.attackData = {isStartAttack= false,endPos = Vector3.New(),
                       stage = 0,isWait = false,isWin = false,actionDuring = 0,
                       startTimeStamp = 0,fightTotalTime = 0,delayTime = 0,inBattleMoveTime = 0}--攻击数据
    local rebornTime = dataTable.getGlobalInt(351)/1000
    self.rebornData = {canReborn = true,isStartReborn = false,
                       maxTime = rebornTime,time = 0,rebornPos = Vector3.New()} --复活数据
end
function PlayerAi:OnDestroy()
    self.destinationData = nil
    self.attackData = nil
    self.rebornData = nil
    self.PursuitData = nil
end
function PlayerAi:HasTarget()
    return self.actor:HasTarget()
end
function PlayerAi:GetTarget()
    return RedRob.ActorManager.GetActor(self.actor.targetId)
end
function PlayerAi:GetTargetPos()
    local target = self:GetTarget()
    if not target then return nil end
    return target:GetPos()
end
function PlayerAi:Update(dt)
    self:UpdateDestination(dt)
    self:UpdatePursuit(dt)
    self:UpdateAttackStage(dt)
    self:UpdateReborn(dt)
end
--region 移动
---endDirection 0: right 朝向 ,1: left ,-1 or nil:不设置最终朝向
function PlayerAi:CreateDestinationData(x,y,endDirection,callback)
    local data = self.destinationData
    data.isStart = true
    data.targetPos:Set(x,y,0)
    data.callback = callback
    data.isFinished = false
    if endDirection == nil then endDirection = -1 end
    data.endDirection = endDirection
    data.startPos:SetV(self.actor:GetPos())
    data.time = 0
    local speed = self.actor:GetAttr(EnumConst.FighterAttributeEnum.SPEED)
    data.maxTime = Vector3.Distance(data.startPos,data.targetPos)/speed
    if data.maxTime <= 0.000001 then
        data.maxTime = 0.000001
    end
    self.actor:SetDir(data.targetPos.x < data.startPos.x)
    self:Print("PlayerAi:CreateDestination",data.maxTime,speed)
end
function PlayerAi:UpdateDestination(dt)
    local data = self.destinationData
    if not data.isStart then return end

    data.time = data.time + dt
    local t = data.time/data.maxTime
    local vec = Vector3.GetCacheVec()
    Vector3.Lerp2(data.startPos,data.targetPos,t,vec)
    self.actor:SetPosByVec(vec)
    Vector3.ReturnToPool(vec)
    if t >= 1 then
        data.isFinished = true
        data.isStart = false
        if data.endDirection ~= -1 then
            self.actor:SetDir(data.endDirection == 1)
        end
        self.actor:EnterState(RedRob.Config.ActionState.idle)
        local cb = data.callback
        if cb then
            data.callback = nil
            cb()
        end
        self:SendMoveMsg(data.targetPos.x,data.targetPos.y)
        if self.attackData.isStartAttack then
            self:Print("PlayerAi:Destination done")
        end
        return
    end
    data.sendMsgTime = data.sendMsgTime - dt
    if data.sendMsgTime <= 0 then
        data.sendMsgTime = data.sendMsgInterval
        self:SendMoveMsg(data.targetPos.x,data.targetPos.y)
    end
end
function PlayerAi:SendMoveMsg(endX,endY)
    if self.attackData.isStartAttack then
        return
    end
    if self.actor == RedRob.KeyController.GetCtrl() then
        local cur = self.actor:GetPos()
        RedRob.BattleMsgHandler.ReqMove(cur.x,cur.y,endX,endY)
    end
end
---endDirection 0: right 朝向 ,1: left ,-1 or nil:不设置最终朝向
function PlayerAi:MoveToDestinationByXYZ(x,y,endDirection,callback)
    self:CreateDestinationData(x,y,endDirection,callback)
    self.actor:EnterState(RedRob.Config.ActionState.run)
    self:SendMoveMsg(x,y)
    self:UpdateDestination(0.001)
end
function PlayerAi:CancelMoveToDestination(toIdle)
    if self.destinationData.isStart then
        self.destinationData.isStart = false
        self.destinationData.isFinished = false
    end
    if toIdle then
        self.actor:EnterState(RedRob.Config.ActionState.idle)
    end
end

--追击目标
---@param target RedRob.Player
function PlayerAi:PursuitTarget(target,rangeRadius,callback,useCenter)
    local data = self.PursuitData
    data.isStart = true
    data.inRangeRadius = rangeRadius
    data.target = target
    data.callback = callback
    data.useCenter = useCenter
    data.isWait = false
    self:UpdatePursuit(0.001)
end
function PlayerAi:UpdatePursuit(dt)
    local data = self.PursuitData
    if not data.isStart then return end
    if data.target:IsDead() then
        self:CancelAttack(true)
        return
    end
    if data.isWait then
        self:CheckAttackPos()
    else
        data.isWait = true
        self:MoveToAttackPos()
    end
end
function PlayerAi:CancelPursuit()
    self.PursuitData.isStart = false
    self.PursuitData.target = nil
    self.PursuitData.callback = nil
end
--endregion 移动
--region 攻击
---@param target RedRob.Pawn
function PlayerAi:Fight(target,damage)
    self:CancelPursuit()
    self:CancelMoveToDestination(false)
    self.actor:SetAttackValue(damage)
    self.actor:SetTarget(target)
    self.actor:SetDir(target:GetPos().x < self.actor:GetPos().x)
    self.actor:SetInBattle(true)
    self.actor:Attack()
    local skill = self.actor.skillMgr:GetEquippedSkill(RedRob.Config.SkillShowType.normalAttack)
    skill:RegisterCallback(RedRob.Config.SkillCallbackType.skillEnd,self,self.FightFinished,true)
end
---@param context BaseContext
function PlayerAi:FightFinished(context)
    self.actor:SetInBattle(false)
    self.actor:SetTarget(nil)
end
function PlayerAi:FightPlayer(target,isWin,startTimeStamp, totalTime, x, y)
    self.attackData.isStartAttack = true
    self.attackData.isWin = isWin
    self.attackData.endPos:Set(x,y)
    self.attackData.startTimeStamp = startTimeStamp
    self.attackData.fightTotalTime = totalTime
    self.actor:SetTarget(target)
    local skill = self.actor.skillMgr:GetEquippedSkill(RedRob.Config.SkillShowType.normalAttack)
    skill:UnRegisterCallback(RedRob.Config.SkillCallbackType.skillEnd,self,self.FightFinished)
    self.actor:SetInBattle(true)
    self:CancelPursuit()
    self:CancelMoveToDestination(false)
    self:EnterAttackStage(RedRob.Config.AttackStage.inBattle)

end
function PlayerAi:EnterAttackStage(stage)
    self:Print("Player:EnterAttackStage",stage)
    self.actor:SetReady(stage >= RedRob.Config.AttackStage.readyToFight)
    self.attackData.stage = stage
    self.attackData.isWait = false
    self:UpdateAttackStage(0.001)
end

function PlayerAi:GetAttackPos(IsInBattlePos)
    local target = self.PursuitData.target
    if IsInBattlePos then
        target = self:GetTarget()
    end
    if not target then return nil end
    local p = target:GetPos()
    local s = self.actor:GetPos()
    local targetPos =  Vector3.GetCacheVec()
    local radius = self.actor:GetAttackRadius()
    local offset = 0.01 --攻击半径往里走点，否则刚好在半径上，CheckAttackPos检测就有问题
    if IsInBattlePos then
        targetPos:Set(self.attackData.endPos.x,self.attackData.endPos.y)
        --[[local centerV = Vector3.GetCacheVec()
        centerV:SetV(p):Add(s):Div(2) --中心点
        if p.x > s.x then
            targetPos:Set(centerV.x - radius+offset,centerV.y,centerV.z)
        else
            targetPos:Set(centerV.x + radius-offset,centerV.y,centerV.z)
        end
        Vector3.ReturnToPool(centerV)]]
    else
        targetPos:SetV(p)
    end
    local x,y = targetPos.x,targetPos.y
    Vector3.ReturnToPool(targetPos)
    return x,y
end
function PlayerAi:MoveToAttackPos(IsInBattlePos)
    local x,y = self:GetAttackPos(IsInBattlePos)
    self:Print("PlayerAi:MoveToAttackPos",tostring(x),tostring(y))
    self:MoveToDestinationByXYZ(x,y)
    if self.destinationData.isFinished then
        self:UpdateAttackStage(0.001)
    end
end
function PlayerAi:CancelAttack(toIdle)
    self.attackData.isStartAttack = false
    self.actor:SetInBattle(false)
    self.actor:SetTarget(nil)
    self:CancelPursuit()
    self:CancelMoveToDestination(toIdle)
end
function PlayerAi:UpdateAttackStage(dt)
    local data = self.attackData
    if not data.isStartAttack then
        return
    end
    local target = self:GetTarget()
    if not target then
        --self:CancelAttackToIdle(true)
        --print("目标消失")
        return
    end
    local STAGE = RedRob.Config.AttackStage
    local isWait = data.isWait
    data.isWait = true
    if data.stage == STAGE.inBattle then
        if target:IsDead() then
            self:CancelAttack(true)
            return
        end
        if isWait then
            data.inBattleMoveTime = data.inBattleMoveTime + dt
            if self.destinationData.isFinished then
                self.actor:SetDir(self:GetTargetPos().x < self.actor:GetPos().x)
                self:EnterAttackStage(STAGE.readyToFight)
            end
        else
            data.inBattleMoveTime = 0
            data.inBattleMoveTime = data.inBattleMoveTime +dt
            self:MoveToAttackPos(true)
        end
    elseif data.stage == STAGE.readyToFight then
        if target:IsDead() then
            self:CancelAttack(true)
            return
        end
        if target:IsReady() then
            self:EnterAttackStage(STAGE.attack)
        end
    elseif data.stage == STAGE.attack then
        local time = RedRob.ClientBattle.GetBattleTime() - data.startTimeStamp
        if not isWait then
            local remainTime = data.fightTotalTime-data.inBattleMoveTime
            local during = self.actor:GetSkillDuring(RedRob.Config.SkillShowType.normalAttack)
            local count
            local damage
            if data.isWin then
                count = math.max(1,math.floor(remainTime/during))
            else
                count = math.max(1,math.ceil(remainTime/during))
            end
            damage = self:GetTarget():GetHpMax() - self:GetTarget().lockHp
            self:Print("Attack:damage:count",damage,count)
            self.actor:SetAttackValue(math.ceil(damage/count))
            FireEvent(RedRob.Config.Event.PlayerFight,self.actor,data.isWin,remainTime)
        end
        if time >= (data.fightTotalTime+0.1) or (self:GetTarget():IsDead() and self.actor:IsInIdle()) then
            if data.isWin then
                self.actor:Win()
                self:EnterAttackStage(STAGE.battleFinished)
            else
                --print("failed ",self.actor:GetAnimStateDuring("death"),"curTime"..RedRob.ClientBattle.GetBattleTime(),"startTime:"..data.startTimeStamp,data.fightTotalTime)
                self.actor:Hurt(self.actor:GetHp(),self:GetTarget(),true)
                self:EnterAttackStage(STAGE.failed)
            end
        else
            self.actor:Attack()
        end
    elseif data.stage == STAGE.win then --最低1秒等待
    elseif data.stage == STAGE.failed then--最低2秒等待
        local during = 2--self.actor:GetAnimStateDuring("death")
        local time = RedRob.ClientBattle.GetBattleTime() - data.startTimeStamp - data.fightTotalTime
        if time >= during then
            self:EnterAttackStage(STAGE.battleFinished)
        end
    elseif data.stage == STAGE.battleFinished then
        if self.actor:IsDead() then
            self:CancelAttack(true)
            self:CheckReborn()
        else
            self.actor:SetHp(self.actor:GetHpMax())
            self:CancelAttack(true)
        end
    end
    --加个保护措施
    --[[if data.stage < STAGE.battleFinished and RedRob.ClientBattle.GetBattleTime() > data.startTimeStamp + data.fightTotalTime +3 then
        self:Print("强制结束战斗")
        self.actor:SetHp(self.actor:GetHpMax())
        self:CancelAttack(true)
    end]]
end
function PlayerAi:CheckAttackPos()
    local target = self.PursuitData.target
    if target == nil then
        return
    end
    local data = self.PursuitData
    local p1 = Vector3.GetCacheVec():SetV(self.actor:GetPos())
    if data.useCenter then
        p1.y = p1.y + self.actor.height/2
    end
    local dSqr = Vector3.SqrDistance(p1,target:GetPos())
    local radiusSqr = data.inRangeRadius * data.inRangeRadius
    if dSqr <= radiusSqr + 0.001 then
        data.isStart = false
        local callback = data.callback
        self:CancelPursuit()
        self:CancelMoveToDestination(true)
        if callback then
            callback()
        end
        --[[if target:IsInBattle() then
            self:CancelAttack(true)
            --print("目标已经战斗")
            return
        end
        self.actor:GotoFight(self.actor,HelperFunc.GetServerTime(),5)
        target:GotoFight(self.actor,HelperFunc.GetServerTime(),5)]]
    else
        local x,y,z = self:GetAttackPos(false)
        local pos = Vector3.GetCacheVec():Set(x,y,z)
        dSqr = Vector3.SqrDistance(self.destinationData.targetPos,pos)
        Vector3.ReturnToPool(pos)
        if dSqr > 0.1 then
            self:MoveToAttackPos()
        end
    end
end
--endregion 攻击
--region 复活
function PlayerAi:CheckReborn()
    if self.rebornData.canReborn then
        self.rebornData.isStartReborn = true
        self.rebornData.time = 0
        self.rebornData.rebornPos:Set(RedRob.ClientBattle.GetLimitRandomPos())
        self.actor:StartReborn(self.rebornData.maxTime)
    end
end
function PlayerAi:UpdateReborn(dt)
    if not self.rebornData.isStartReborn then return end
    local data = self.rebornData
    data.time = data.time + dt
    if data.time >= data.maxTime then
        data.isStartReborn = false
        --waiting server
        --self.actor:Reborn(data.rebornPos.x,data.rebornPos.y)
    end
end
--endregion 复活